#include <cmath>
#include <stdio.h>
#include <iostream>
#include "../include/Image.h"
#include "../include/Pixel.h"



Image::Image(int _l,int _h):largeur(_l),hauteur(_h)
{
	data = new Pixel[largeur*hauteur];
	//histo = new Histogramme(1000,this);
	sprite = NULL;
}

Image::~Image(){

	//delete []histo;
	delete []data;
	delete []sprite;
}

Image* Image::CopierImage(){
	Image* out = new Image(largeur,hauteur);
	for (int i = 0; i < largeur; i++){
		for (int j = 0; j < hauteur ; j++){
		   out->EcritPixel(i,j,this->LitPixel(i,j));
		}
	}
	return out;
}

int Image::chargePPM (const char *nom)
{
	FILE *f;
	char s[2048];
	int width, height, maxgrey, n, k;
	unsigned char ligne[2048];
	char * t;
	
	if(data!=NULL)
		delete [] data;
	data = NULL;
	
	/* Ouverture du fichier */
	f = fopen (nom, "rb");
	if (f == NULL)
			{
			printf ("ERREUR fopen(%s)\n", nom);
			return -1;
			}

	/* Lecture MagicValue
	 * On evite fscanf pour eviter buffer overflow */
	t = fgets (s, 2048, f);
	if (s[0] != 'P' || s[1] != '6')
			{
			printf ("ERREUR MagicValue <> P6\n");
			fclose (f);
			return -1;
			}

	/* Lecture width height
	 * On saute les ligne commencant par un '#' */
	do t = fgets (s, 2048, f);
	while (s[0] == '#');
	sscanf (s, "%d %d", &width, &height);
	
	largeur = width;
	hauteur = height;

	/* Lecture maxgrey
	 * On ne tient pas compte de maxgrey, qui est presque toujours 255.
	 * On saute les ligne commencant par un '#' */
	do t = fgets (s, 2048, f);
	while (s[0] == '#');
	sscanf (s, "%d", &maxgrey);
	data = new Pixel[width*height];

	/* Lecture image */
	for (n=0;n<height;n++)
			{
			if(fread(ligne,sizeof(unsigned char)*width*3,1,f)!=1)
				return -1;
			for (k=0;k<width*3;k+=3){
					data[n*width+k/3] = Pixel(ligne[k],ligne[k+1],ligne[k+2]);
				}
			}
	fclose (f);
	return 0;
}

int Image::sauvePPM (const char *nom){
	
	FILE *f;
	int n,k;
	unsigned char ligne[2048];

	f = fopen (nom, "wb");
	if (f == NULL)
	{
		printf ("ERREUR fopen(%s)\n", nom);
		return -1;
	}

	fprintf (f, "P6\n");
	fprintf (f, "# width height\n");
	fprintf (f, "%d %d\n", largeur, hauteur);
	fprintf (f, "255\n");

	for (n=0;n<hauteur;n++)
	{
		for (k=0;k<largeur*3;k+=3){
			ligne[k]=(unsigned char)data[n*largeur+k/3].getR();
			ligne[k+1]=(unsigned char)data[n*largeur+k/3].getV();
			ligne[k+2]=(unsigned char)data[n*largeur+k/3].getB();
		}
		if (fwrite (ligne, sizeof(unsigned char)*largeur*3,1,f)!=1)
		{
			printf ("ERREUR fwrite()\n");
			fclose (f);
			return -1;
		}
	}

	fclose (f);
	return 0;

}

Pixel Image::LitPixel(int x, int y)
{
	if (x < 0)
		x = -x;
	else if (x >= largeur)
		x = largeur*2 - 1 - x;
	if (y < 0)
		y = -y;
	else if (y >= hauteur)
		y = hauteur*2 -1 - y;
	return data[y*largeur + x];
}

void Image::EcritPixel(int x, int y, Pixel couleur)
{
	if (x < 0)
		x = -x;
	else if (x >= largeur)
		x = largeur*2 - 1 - x;
	if (y < 0)
		y = -y;
	else if (y >= hauteur)
		y = hauteur*2 -1 - y;
	data[y*largeur + x] = couleur;
}

Image* Image::FiltrageLineaire(FiltreLineaire *fl){
	Image* out = new Image(largeur,hauteur);
	int b = (int)fl->taille/2;
	for(int i=0;i<hauteur;i++){
		for(int j=0;j<largeur;j++){
			Pixel s;
			int n=0;
			for(int k=i-b;k<=i+b;k++){
				for(int l=j-b;l<=j+b;l++){
					s+=LitPixel(l,k)*fl->coef[n++];
				}
			}
			out->EcritPixel(j,i,s);
		}
	}
	return out;
}

void Image::Afficher(){
	if(sprite!=NULL)
		glDrawPixels(largeur, hauteur, GL_RGB, GL_UNSIGNED_BYTE, sprite) ;
}

void Image::toSprite(){
	
	int x;
	if(sprite != NULL)
		delete []sprite;
			
	sprite = new GLubyte[hauteur*largeur*3];
	
	for (int y=0 ; y < hauteur; y++)
	{
		for (x=0 ; x < largeur*3 ; x+=3)
		{
			sprite[(hauteur-1-y)*largeur*3+x] = (GLubyte)LitPixel(x/3,y).getR() ;
			sprite[(hauteur-1-y)*largeur*3+x+1] = (GLubyte)LitPixel(x/3,y).getV();
			sprite[(hauteur-1-y)*largeur*3+x+2] = (GLubyte)LitPixel(x/3,y).getB();
		}
	}
}

Image* Image::Laplacien(){
	Image* laplacien;
	FiltreLineaire fl;
	float tmp[9] = {0,1,0,1,-4,1,0,1,0};
	
	fl.taille = 3;
	fl.coef = new float[3*3];
	for(int i = 0;i<fl.taille*fl.taille;i++){
		fl.coef[i] = tmp[i];
	}
	laplacien = FiltrageLineaire(&fl);
	return laplacien;
}
